Sketch a new interface for transferring hypercall arguments in memory.
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Tue, 28 Feb 2006 16:45:20 +0000 (17:45 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Tue, 28 Feb 2006 16:45:20 +0000 (17:45 +0100)
Instead of manipulating guest virtual addresses, 'guest handles' are
passed across the hypercall interface, which may only be manipulated
via the interface exported by guest_access.h.

So far this has only been applied to the memory_op hypercall. The
interfaces are still subject to change. Other hypercalls can be updated
after the interface is agreed upon.

Also cleaned up the hypercall_create_continuation() interface to take
a format string and different-typed varargs (they do not all need to
be castable to longs).

Signed-off-by: Keir Fraser <keir@xensource.com>
16 files changed:
xen/Rules.mk
xen/arch/ia64/vmx/vmx_hypercall.c
xen/arch/ia64/xen/process.c
xen/arch/x86/domain.c
xen/arch/x86/mm.c
xen/arch/x86/traps.c
xen/arch/x86/x86_32/mm.c
xen/arch/x86/x86_64/mm.c
xen/common/memory.c
xen/common/multicall.c
xen/drivers/char/console.c
xen/include/asm-x86/mm.h
xen/include/public/memory.h
xen/include/public/xen.h
xen/include/xen/guest_access.h [new file with mode: 0644]
xen/include/xen/sched.h

index 25478ec43411afb6bf09c71f79e1ee636062ad4e..8fbae5270fe217b48d897391f05bd628823632da 100644 (file)
@@ -45,7 +45,7 @@ ALL_OBJS += $(BASEDIR)/arch/$(TARGET_ARCH)/arch.o
 
 include $(BASEDIR)/arch/$(TARGET_ARCH)/Rules.mk
 
-CFLAGS += -g
+CFLAGS += -g -D__XEN__
 
 ifneq ($(debug),y)
 CFLAGS += -DNDEBUG
index 75c1cc9fb2121e6710c3c8e59fba1b10875215f3..b7fde636e76807cb760b69d8e9e6bcbec82e1a7a 100644 (file)
@@ -52,45 +52,7 @@ void hyper_mmu_update(void)
     vcpu_set_gr(vcpu, 8, ret, 0);
     vmx_vcpu_increment_iip(vcpu);
 }
-/* turn off temporarily, we will merge hypercall parameter convention with xeno, when
-    VTI domain need to call hypercall */
-#if 0
-unsigned long __hypercall_create_continuation(
-    unsigned int op, unsigned int nr_args, ...)
-{
-    struct mc_state *mcs = &mc_state[smp_processor_id()];
-    VCPU *vcpu = current;
-    struct cpu_user_regs *regs = vcpu_regs(vcpu);
-    unsigned int i;
-    va_list args;
-
-    va_start(args, nr_args);
-    if ( test_bit(_MCSF_in_multicall, &mcs->flags) ) {
-       panic("PREEMPT happen in multicall\n"); // Not support yet
-    } else {
-       vcpu_set_gr(vcpu, 15, op, 0);
-       for ( i = 0; i < nr_args; i++) {
-           switch (i) {
-           case 0: vcpu_set_gr(vcpu, 16, va_arg(args, unsigned long), 0);
-                   break;
-           case 1: vcpu_set_gr(vcpu, 17, va_arg(args, unsigned long), 0);
-                   break;
-           case 2: vcpu_set_gr(vcpu, 18, va_arg(args, unsigned long), 0);
-                   break;
-           case 3: vcpu_set_gr(vcpu, 19, va_arg(args, unsigned long), 0);
-                   break;
-           case 4: vcpu_set_gr(vcpu, 20, va_arg(args, unsigned long), 0);
-                   break;
-           default: panic("Too many args for hypercall continuation\n");
-                   break;
-           }
-       }
-    }
-    vcpu->arch.hypercall_continuation = 1;
-    va_end(args);
-    return op;
-}
-#endif
+
 void hyper_dom_mem_op(void)
 {
     VCPU *vcpu=current;
index 0823c9423f5fae89882e7a1a291e78b484a25f59..7ecfabf01ededd1f7b4ed7c162375ab4d2a47e9b 100644 (file)
@@ -796,31 +796,49 @@ printf("*** Handled privop masquerading as NaT fault\n");
        reflect_interruption(isr,regs,vector);
 }
 
-unsigned long __hypercall_create_continuation(
-       unsigned int op, unsigned int nr_args, ...)
+unsigned long hypercall_create_continuation(
+       unsigned int op, const char *format, ...)
 {
     struct mc_state *mcs = &mc_state[smp_processor_id()];
     VCPU *vcpu = current;
     struct cpu_user_regs *regs = vcpu_regs(vcpu);
+    const char *p = format;
+    unsigned long arg;
     unsigned int i;
     va_list args;
 
-    va_start(args, nr_args);
+    va_start(args, format);
     if ( test_bit(_MCSF_in_multicall, &mcs->flags) ) {
        panic("PREEMPT happen in multicall\n"); // Not support yet
     } else {
        vcpu_set_gr(vcpu, 2, op, 0);
-       for ( i = 0; i < nr_args; i++) {
+       for ( i = 0; *p != '\0'; i++) {
+            switch ( *p++ )
+            {
+            case 'i':
+                arg = (unsigned long)va_arg(args, unsigned int);
+                break;
+            case 'l':
+                arg = (unsigned long)va_arg(args, unsigned long);
+                break;
+            case 'p':
+            case 'h':
+                arg = (unsigned long)va_arg(args, void *);
+                break;
+            default:
+                arg = 0;
+                BUG();
+            }
            switch (i) {
-           case 0: vcpu_set_gr(vcpu, 14, va_arg(args, unsigned long), 0);
+           case 0: vcpu_set_gr(vcpu, 14, arg, 0);
                    break;
-           case 1: vcpu_set_gr(vcpu, 15, va_arg(args, unsigned long), 0);
+           case 1: vcpu_set_gr(vcpu, 15, arg, 0);
                    break;
-           case 2: vcpu_set_gr(vcpu, 16, va_arg(args, unsigned long), 0);
+           case 2: vcpu_set_gr(vcpu, 16, arg, 0);
                    break;
-           case 3: vcpu_set_gr(vcpu, 17, va_arg(args, unsigned long), 0);
+           case 3: vcpu_set_gr(vcpu, 17, arg, 0);
                    break;
-           case 4: vcpu_set_gr(vcpu, 18, va_arg(args, unsigned long), 0);
+           case 4: vcpu_set_gr(vcpu, 18, arg, 0);
                    break;
            default: panic("Too many args for hypercall continuation\n");
                    break;
index df61b9b9aa91b2a0b976a6fecd826780024f20c3..b383683e7085f44615ff52b77d2c7179c50d2fb9 100644 (file)
@@ -825,22 +825,37 @@ void sync_vcpu_execstate(struct vcpu *v)
     flush_tlb_mask(v->vcpu_dirty_cpumask);
 }
 
-unsigned long __hypercall_create_continuation(
-    unsigned int op, unsigned int nr_args, ...)
+#define next_arg(fmt, args) ({                                              \
+    unsigned long __arg;                                                    \
+    switch ( *(fmt)++ )                                                     \
+    {                                                                       \
+    case 'i': __arg = (unsigned long)va_arg(args, unsigned int);  break;    \
+    case 'l': __arg = (unsigned long)va_arg(args, unsigned long); break;    \
+    case 'p': __arg = (unsigned long)va_arg(args, void *);        break;    \
+    case 'h': __arg = (unsigned long)va_arg(args, void *);        break;    \
+    default:  __arg = 0; BUG();                                             \
+    }                                                                       \
+    __arg;                                                                  \
+})
+
+unsigned long hypercall_create_continuation(
+    unsigned int op, const char *format, ...)
 {
     struct mc_state *mcs = &mc_state[smp_processor_id()];
     struct cpu_user_regs *regs;
+    const char *p = format;
+    unsigned long arg;
     unsigned int i;
     va_list args;
 
-    va_start(args, nr_args);
+    va_start(args, format);
 
     if ( test_bit(_MCSF_in_multicall, &mcs->flags) )
     {
         __set_bit(_MCSF_call_preempted, &mcs->flags);
 
-        for ( i = 0; i < nr_args; i++ )
-            mcs->call.args[i] = va_arg(args, unsigned long);
+        for ( i = 0; *p != '\0'; i++ )
+            mcs->call.args[i] = next_arg(p, args);
     }
     else
     {
@@ -853,32 +868,34 @@ unsigned long __hypercall_create_continuation(
         else
             regs->eip -= 2;   /* re-execute 'int 0x82' */
 
-        for ( i = 0; i < nr_args; i++ )
+        for ( i = 0; *p != '\0'; i++ )
         {
+            arg = next_arg(p, args);
             switch ( i )
             {
-            case 0: regs->ebx = va_arg(args, unsigned long); break;
-            case 1: regs->ecx = va_arg(args, unsigned long); break;
-            case 2: regs->edx = va_arg(args, unsigned long); break;
-            case 3: regs->esi = va_arg(args, unsigned long); break;
-            case 4: regs->edi = va_arg(args, unsigned long); break;
-            case 5: regs->ebp = va_arg(args, unsigned long); break;
+            case 0: regs->ebx = arg; break;
+            case 1: regs->ecx = arg; break;
+            case 2: regs->edx = arg; break;
+            case 3: regs->esi = arg; break;
+            case 4: regs->edi = arg; break;
+            case 5: regs->ebp = arg; break;
             }
         }
 #elif defined(__x86_64__)
         regs->rax  = op;
         regs->rip -= 2;  /* re-execute 'syscall' */
 
-        for ( i = 0; i < nr_args; i++ )
+        for ( i = 0; *p != '\0'; i++ )
         {
+            arg = next_arg(p, args);
             switch ( i )
             {
-            case 0: regs->rdi = va_arg(args, unsigned long); break;
-            case 1: regs->rsi = va_arg(args, unsigned long); break;
-            case 2: regs->rdx = va_arg(args, unsigned long); break;
-            case 3: regs->r10 = va_arg(args, unsigned long); break;
-            case 4: regs->r8  = va_arg(args, unsigned long); break;
-            case 5: regs->r9  = va_arg(args, unsigned long); break;
+            case 0: regs->rdi = arg; break;
+            case 1: regs->rsi = arg; break;
+            case 2: regs->rdx = arg; break;
+            case 3: regs->r10 = arg; break;
+            case 4: regs->r8  = arg; break;
+            case 5: regs->r9  = arg; break;
             }
         }
 #endif
index 371cc782795ff6fd7f89aec1b099a49c95b19071..321d2b9deed8aa47f8d27ab13f51c6ae1040b105 100644 (file)
 #include <xen/domain_page.h>
 #include <xen/event.h>
 #include <xen/iocap.h>
+#include <xen/guest_access.h>
 #include <asm/shadow.h>
 #include <asm/page.h>
 #include <asm/flushtlb.h>
 #include <asm/io.h>
-#include <asm/uaccess.h>
 #include <asm/ldt.h>
 #include <asm/x86_emulate.h>
 #include <public/memory.h>
@@ -1778,9 +1778,9 @@ int do_mmuext_op(
     {
         if ( hypercall_preempt_check() )
         {
-            rc = hypercall4_create_continuation(
-                __HYPERVISOR_mmuext_op, uops,
-                (count - i) | MMU_UPDATE_PREEMPTED, pdone, foreigndom);
+            rc = hypercall_create_continuation(
+                __HYPERVISOR_mmuext_op, "pipi",
+                uops, (count - i) | MMU_UPDATE_PREEMPTED, pdone, foreigndom);
             break;
         }
 
@@ -2044,9 +2044,9 @@ int do_mmu_update(
     {
         if ( hypercall_preempt_check() )
         {
-            rc = hypercall4_create_continuation(
-                __HYPERVISOR_mmu_update, ureqs, 
-                (count - i) | MMU_UPDATE_PREEMPTED, pdone, foreigndom);
+            rc = hypercall_create_continuation(
+                __HYPERVISOR_mmu_update, "pipi",
+                ureqs, (count - i) | MMU_UPDATE_PREEMPTED, pdone, foreigndom);
             break;
         }
 
@@ -2795,7 +2795,7 @@ long do_update_descriptor(u64 pa, u64 desc)
 }
 
 
-long arch_memory_op(int op, void *arg)
+long arch_memory_op(int op, GUEST_HANDLE(void) arg)
 {
     struct xen_reserved_phys_area xrpa;
     unsigned long pfn;
@@ -2805,7 +2805,7 @@ long arch_memory_op(int op, void *arg)
     switch ( op )
     {
     case XENMEM_reserved_phys_area:
-        if ( copy_from_user(&xrpa, arg, sizeof(xrpa)) )
+        if ( copy_from_guest(&xrpa, arg, 1) )
             return -EFAULT;
 
         /* No guest has more than one reserved area. */
@@ -2839,7 +2839,7 @@ long arch_memory_op(int op, void *arg)
 
         put_domain(d);
 
-        if ( copy_to_user(arg, &xrpa, sizeof(xrpa)) )
+        if ( copy_to_guest(arg, &xrpa, 1) )
             return -EFAULT;
 
         break;
index bd590c70ce315de6f9f3f9aba25063b1092c9159..2dabc44c31b1df9863803a1a2392542fa2af91bc 100644 (file)
@@ -1415,8 +1415,8 @@ long do_set_trap_table(struct trap_info *traps)
     {
         if ( hypercall_preempt_check() )
         {
-            rc = hypercall1_create_continuation(
-                __HYPERVISOR_set_trap_table, traps);
+            rc = hypercall_create_continuation(
+                __HYPERVISOR_set_trap_table, "p", traps);
             break;
         }
 
index 70dfe77babcbac07f0a11758e49676ee70f82cb1..19dfc0170e90fde75ee6e51eac7a120cf50b5648 100644 (file)
@@ -23,6 +23,7 @@
 #include <xen/init.h>
 #include <xen/mm.h>
 #include <xen/sched.h>
+#include <xen/guest_access.h>
 #include <asm/current.h>
 #include <asm/page.h>
 #include <asm/flushtlb.h>
@@ -191,7 +192,7 @@ void subarch_init_memory(struct domain *dom_xen)
     }
 }
 
-long subarch_memory_op(int op, void *arg)
+long subarch_memory_op(int op, GUEST_HANDLE(void) arg)
 {
     struct xen_machphys_mfn_list xmml;
     unsigned long mfn;
@@ -201,7 +202,7 @@ long subarch_memory_op(int op, void *arg)
     switch ( op )
     {
     case XENMEM_machphys_mfn_list:
-        if ( copy_from_user(&xmml, arg, sizeof(xmml)) )
+        if ( copy_from_guest(&xmml, arg, 1) )
             return -EFAULT;
 
         max = min_t(unsigned int, xmml.max_extents, mpt_size >> 21);
@@ -210,11 +211,12 @@ long subarch_memory_op(int op, void *arg)
         {
             mfn = l2e_get_pfn(idle_pg_table_l2[l2_linear_offset(
                 RDWR_MPT_VIRT_START + (i << 21))]) + l1_table_offset(i << 21);
-            if ( put_user(mfn, &xmml.extent_start[i]) )
+            if ( copy_to_guest_offset(xmml.extent_start, i, &mfn, 1) )
                 return -EFAULT;
         }
 
-        if ( put_user(i, &((struct xen_machphys_mfn_list *)arg)->nr_extents) )
+        xmml.nr_extents = i;
+        if ( copy_to_guest(arg, &xmml, 1) )
             return -EFAULT;
 
         break;
index 855a6510f2ed735d47d6d4e100e8bde2a8d35c1d..7e826da8b098ef85e16eb899a18b6dd720b268f8 100644 (file)
@@ -22,6 +22,7 @@
 #include <xen/init.h>
 #include <xen/mm.h>
 #include <xen/sched.h>
+#include <xen/guest_access.h>
 #include <asm/current.h>
 #include <asm/asm_defns.h>
 #include <asm/page.h>
@@ -182,7 +183,7 @@ void subarch_init_memory(struct domain *dom_xen)
     }
 }
 
-long subarch_memory_op(int op, void *arg)
+long subarch_memory_op(int op, GUEST_HANDLE(void) arg)
 {
     struct xen_machphys_mfn_list xmml;
     l3_pgentry_t l3e;
@@ -194,7 +195,7 @@ long subarch_memory_op(int op, void *arg)
     switch ( op )
     {
     case XENMEM_machphys_mfn_list:
-        if ( copy_from_user(&xmml, arg, sizeof(xmml)) )
+        if ( copy_from_guest(&xmml, arg, 1) )
             return -EFAULT;
 
         for ( i = 0, v = RDWR_MPT_VIRT_START;
@@ -209,11 +210,12 @@ long subarch_memory_op(int op, void *arg)
             if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) )
                 break;
             mfn = l2e_get_pfn(l2e) + l1_table_offset(v);
-            if ( put_user(mfn, &xmml.extent_start[i]) )
+            if ( copy_to_guest_offset(xmml.extent_start, i, &mfn, 1) )
                 return -EFAULT;
         }
 
-        if ( put_user(i, &((struct xen_machphys_mfn_list *)arg)->nr_extents) )
+        xmml.nr_extents = i;
+        if ( copy_to_guest(arg, &xmml, 1) )
             return -EFAULT;
 
         break;
index 40a2d9c14d43e127ad510bffa9c6a51a57abe304..4d96f97465c8ac8fbf8961a5f8705e45cc30407b 100644 (file)
@@ -16,6 +16,7 @@
 #include <xen/event.h>
 #include <xen/shadow.h>
 #include <xen/iocap.h>
+#include <xen/guest_access.h>
 #include <asm/current.h>
 #include <asm/hardirq.h>
 #include <public/memory.h>
@@ -30,7 +31,7 @@
 static long
 increase_reservation(
     struct domain *d, 
-    unsigned long *extent_list, 
+    GUEST_HANDLE(xen_ulong) extent_list,
     unsigned int   nr_extents,
     unsigned int   extent_order,
     unsigned int   flags,
@@ -39,8 +40,8 @@ increase_reservation(
     struct page_info *page;
     unsigned long     i, mfn;
 
-    if ( (extent_list != NULL) &&
-         !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
+    if ( !guest_handle_is_null(extent_list) &&
+         !guest_handle_okay(extent_list, nr_extents) )
         return 0;
 
     if ( (extent_order != 0) &&
@@ -65,10 +66,10 @@ increase_reservation(
         }
 
         /* Inform the domain of the new page's machine address. */ 
-        if ( extent_list != NULL )
+        if ( !guest_handle_is_null(extent_list) )
         {
             mfn = page_to_mfn(page);
-            if ( unlikely(__copy_to_user(&extent_list[i], &mfn, sizeof(mfn))) )
+            if ( unlikely(__copy_to_guest_offset(extent_list, i, &mfn, 1)) )
                 return i;
         }
     }
@@ -79,16 +80,16 @@ increase_reservation(
 static long
 populate_physmap(
     struct domain *d, 
-    unsigned long *extent_list, 
-    unsigned int   nr_extents,
-    unsigned int   extent_order,
-    unsigned int   flags,
-    int           *preempted)
+    GUEST_HANDLE(xen_ulong) extent_list,
+    unsigned int  nr_extents,
+    unsigned int  extent_order,
+    unsigned int  flags,
+    int          *preempted)
 {
     struct page_info *page;
     unsigned long    i, j, gpfn, mfn;
 
-    if ( !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
+    if ( !guest_handle_okay(extent_list, nr_extents) )
         return 0;
 
     if ( (extent_order != 0) &&
@@ -103,7 +104,7 @@ populate_physmap(
             goto out;
         }
 
-        if ( unlikely(__copy_from_user(&gpfn, &extent_list[i], sizeof(gpfn))) )
+        if ( unlikely(__copy_from_guest_offset(&gpfn, extent_list, i, 1)) )
             goto out;
 
         if ( unlikely((page = alloc_domheap_pages(
@@ -128,7 +129,7 @@ populate_physmap(
                 set_gpfn_from_mfn(mfn + j, gpfn + j);
 
             /* Inform the domain of the new page's machine address. */ 
-            if ( unlikely(__copy_to_user(&extent_list[i], &mfn, sizeof(mfn))) )
+            if ( unlikely(__copy_to_guest_offset(extent_list, i, &mfn, 1)) )
                 goto out;
         }
     }
@@ -139,8 +140,8 @@ populate_physmap(
     
 static long
 decrease_reservation(
-    struct domain *d, 
-    unsigned long *extent_list, 
+    struct domain *d,
+    GUEST_HANDLE(xen_ulong) extent_list,
     unsigned int   nr_extents,
     unsigned int   extent_order,
     unsigned int   flags,
@@ -149,7 +150,7 @@ decrease_reservation(
     struct page_info *page;
     unsigned long    i, j, gmfn, mfn;
 
-    if ( !array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
+    if ( !guest_handle_okay(extent_list, nr_extents) )
         return 0;
 
     for ( i = 0; i < nr_extents; i++ )
@@ -160,7 +161,7 @@ decrease_reservation(
             return i;
         }
 
-        if ( unlikely(__copy_from_user(&gmfn, &extent_list[i], sizeof(gmfn))) )
+        if ( unlikely(__copy_from_guest_offset(&gmfn, extent_list, i, 1)) )
             return i;
 
         for ( j = 0; j < (1 << extent_order); j++ )
@@ -197,21 +198,21 @@ decrease_reservation(
 
 static long
 translate_gpfn_list(
-    struct xen_translate_gpfn_list *uop, unsigned long *progress)
+    GUEST_HANDLE(xen_translate_gpfn_list_t) uop, unsigned long *progress)
 {
     struct xen_translate_gpfn_list op;
     unsigned long i, gpfn, mfn;
     struct domain *d;
 
-    if ( copy_from_user(&op, uop, sizeof(op)) )
+    if ( copy_from_guest(&op, uop, 1) )
         return -EFAULT;
 
     /* Is size too large for us to encode a continuation? */
     if ( op.nr_gpfns > (ULONG_MAX >> START_EXTENT_SHIFT) )
         return -EINVAL;
 
-    if ( !array_access_ok(op.gpfn_list, op.nr_gpfns, sizeof(*op.gpfn_list)) ||
-         !array_access_ok(op.mfn_list, op.nr_gpfns, sizeof(*op.mfn_list)) )
+    if ( !guest_handle_okay(op.gpfn_list, op.nr_gpfns) ||
+         !guest_handle_okay(op.mfn_list,  op.nr_gpfns) )
         return -EFAULT;
 
     if ( op.domid == DOMID_SELF )
@@ -237,8 +238,7 @@ translate_gpfn_list(
             return -EAGAIN;
         }
 
-        if ( unlikely(__copy_from_user(&gpfn, &op.gpfn_list[i],
-                                       sizeof(gpfn))) )
+        if ( unlikely(__copy_from_guest_offset(&gpfn, op.gpfn_list, i, 1)) )
         {
             put_domain(d);
             return -EFAULT;
@@ -246,8 +246,7 @@ translate_gpfn_list(
 
         mfn = gmfn_to_mfn(d, gpfn);
 
-        if ( unlikely(__copy_to_user(&op.mfn_list[i], &mfn,
-                                     sizeof(mfn))) )
+        if ( unlikely(__copy_to_guest_offset(op.mfn_list, i, &mfn, 1)) )
         {
             put_domain(d);
             return -EFAULT;
@@ -258,7 +257,7 @@ translate_gpfn_list(
     return 0;
 }
 
-long do_memory_op(unsigned long cmd, void *arg)
+long do_memory_op(unsigned long cmd, GUEST_HANDLE(void) arg)
 {
     struct domain *d;
     int rc, op, flags = 0, preempted = 0;
@@ -273,7 +272,7 @@ long do_memory_op(unsigned long cmd, void *arg)
     case XENMEM_increase_reservation:
     case XENMEM_decrease_reservation:
     case XENMEM_populate_physmap:
-        if ( copy_from_user(&reservation, arg, sizeof(reservation)) )
+        if ( copy_from_guest(&reservation, arg, 1) )
             return -EFAULT;
 
         /* Is size too large for us to encode a continuation? */
@@ -283,9 +282,9 @@ long do_memory_op(unsigned long cmd, void *arg)
         start_extent = cmd >> START_EXTENT_SHIFT;
         if ( unlikely(start_extent > reservation.nr_extents) )
             return -EINVAL;
-        
-        if ( reservation.extent_start != NULL )
-            reservation.extent_start += start_extent;
+
+        if ( !guest_handle_is_null(reservation.extent_start) )
+            guest_handle_add_offset(reservation.extent_start, start_extent);
         reservation.nr_extents -= start_extent;
 
         if ( (reservation.address_bits != 0) &&
@@ -342,8 +341,9 @@ long do_memory_op(unsigned long cmd, void *arg)
         rc += start_extent;
 
         if ( preempted )
-            return hypercall2_create_continuation(
-                __HYPERVISOR_memory_op, op | (rc << START_EXTENT_SHIFT), arg);
+            return hypercall_create_continuation(
+                __HYPERVISOR_memory_op, "lh",
+                op | (rc << START_EXTENT_SHIFT), arg);
 
         break;
 
@@ -353,10 +353,10 @@ long do_memory_op(unsigned long cmd, void *arg)
 
     case XENMEM_current_reservation:
     case XENMEM_maximum_reservation:
-        if ( copy_from_user(&domid, (domid_t *)arg, sizeof(domid)) )
+        if ( copy_from_guest(&domid, arg, 1) )
             return -EFAULT;
 
-        if ( likely((domid = (unsigned long)arg) == DOMID_SELF) )
+        if ( likely(domid == DOMID_SELF) )
             d = current->domain;
         else if ( !IS_PRIV(current->domain) )
             return -EPERM;
@@ -372,12 +372,13 @@ long do_memory_op(unsigned long cmd, void *arg)
 
     case XENMEM_translate_gpfn_list:
         progress = cmd >> START_EXTENT_SHIFT;
-        rc = translate_gpfn_list(arg, &progress);
+        rc = translate_gpfn_list(
+            guest_handle_cast(arg, xen_translate_gpfn_list_t),
+            &progress);
         if ( rc == -EAGAIN )
-            return hypercall2_create_continuation(
-                __HYPERVISOR_memory_op,
-                op | (progress << START_EXTENT_SHIFT),
-                arg);
+            return hypercall_create_continuation(
+                __HYPERVISOR_memory_op, "lh",
+                op | (progress << START_EXTENT_SHIFT), arg);
         break;
 
     default:
index d6473a8b4b4f06e65ca3dd17a04eea9fc11ec204..823625aad15bc534891208a87baaedf84a172bf2 100644 (file)
@@ -81,8 +81,8 @@ long do_multicall(struct multicall_entry *call_list, unsigned int nr_calls)
             if ( i < nr_calls )
             {
                 mcs->flags = 0;
-                return hypercall2_create_continuation(
-                    __HYPERVISOR_multicall, &call_list[i], nr_calls-i);
+                return hypercall_create_continuation(
+                    __HYPERVISOR_multicall, "pi", &call_list[i], nr_calls-i);
             }
         }
     }
index c11fbf4cf4723d7d2e04bf7f25f97f88ac81694c..7c8b0d6baadf252026a1e17e505094ba745614c5 100644 (file)
@@ -335,8 +335,9 @@ long guest_console_write(char *buffer, int count)
         }
 
         if ( hypercall_preempt_check() )
-            return hypercall3_create_continuation(
-                __HYPERVISOR_console_io, CONSOLEIO_write, count, buffer);
+            return hypercall_create_continuation(
+                __HYPERVISOR_console_io, "iip",
+                CONSOLEIO_write, count, buffer);
 
         kcount = min_t(int, count, sizeof(kbuf)-1);
         if ( copy_from_user(kbuf, buffer, kcount) )
index 468427b099bf4b959ecf0b34be176bc22a40798b..4d7870fb0342b4c40dbbad07a84f72dcd8ef19c9 100644 (file)
@@ -376,7 +376,7 @@ void propagate_page_fault(unsigned long addr, u16 error_code);
 int __sync_lazy_execstate(void);
 
 /* Arch-specific portion of memory_op hypercall. */
-long arch_memory_op(int op, void *arg);
-long subarch_memory_op(int op, void *arg);
+long arch_memory_op(int op, GUEST_HANDLE(void) arg);
+long subarch_memory_op(int op, GUEST_HANDLE(void) arg);
 
 #endif /* __ASM_X86_MM_H__ */
index eb99be99ef4c92c227fe97c9918ff778933f9ae1..639c293b27095453165d4f7930fa749c4397ed65 100644 (file)
@@ -29,7 +29,7 @@ typedef struct xen_memory_reservation {
      *   OUT: GMFN bases of extents that were allocated
      *   (NB. This command also updates the mach_to_phys translation table)
      */
-    unsigned long *extent_start;
+    GUEST_HANDLE(xen_ulong) extent_start;
 
     /* Number of extents, and size/alignment of each (2^extent_order pages). */
     unsigned long  nr_extents;
@@ -50,6 +50,7 @@ typedef struct xen_memory_reservation {
     domid_t        domid;
 
 } xen_memory_reservation_t;
+DEFINE_GUEST_HANDLE(xen_memory_reservation_t);
 
 /*
  * Returns the maximum machine frame number of mapped RAM in this system.
@@ -85,7 +86,7 @@ typedef struct xen_machphys_mfn_list {
      * any large discontiguities in the machine address space, 2MB gaps in
      * the machphys table will be represented by an MFN base of zero.
      */
-    unsigned long *extent_start;
+    GUEST_HANDLE(xen_ulong) extent_start;
 
     /*
      * Number of extents written to the above array. This will be smaller
@@ -93,6 +94,7 @@ typedef struct xen_machphys_mfn_list {
      */
     unsigned int nr_extents;
 } xen_machphys_mfn_list_t;
+DEFINE_GUEST_HANDLE(xen_machphys_mfn_list_t);
 
 /*
  * Returns the base and size of the specified reserved 'RAM hole' in the
@@ -113,6 +115,7 @@ typedef struct xen_reserved_phys_area {
     /* Base and size of the specified reserved area. */
     unsigned long first_gpfn, nr_gpfns;
 } xen_reserved_phys_area_t;
+DEFINE_GUEST_HANDLE(xen_reserved_phys_area_t);
 
 /*
  * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error
@@ -127,14 +130,15 @@ typedef struct xen_translate_gpfn_list {
     unsigned long nr_gpfns;
 
     /* List of GPFNs to translate. */
-    unsigned long *gpfn_list;
+    GUEST_HANDLE(xen_ulong) gpfn_list;
 
     /*
      * Output list to contain MFN translations. May be the same as the input
      * list (in which case each input GPFN is overwritten with the output MFN).
      */
-    unsigned long *mfn_list;
+    GUEST_HANDLE(xen_ulong) mfn_list;
 } xen_translate_gpfn_list_t;
+DEFINE_GUEST_HANDLE(xen_translate_gpfn_list_t);
 
 #endif /* __XEN_PUBLIC_MEMORY_H__ */
 
index 9baf7f0bbe5ae8339428eb5e9fd683b819133af4..a629a1e26a449b8f652a55d409960ec2efc645bd 100644 (file)
@@ -9,6 +9,22 @@
 #ifndef __XEN_PUBLIC_XEN_H__
 #define __XEN_PUBLIC_XEN_H__
 
+#ifdef __XEN__
+#define DEFINE_GUEST_HANDLE(type) struct __guest_handle_ ## type { type *p; }
+#define GUEST_HANDLE(type)        struct __guest_handle_ ## type
+#else
+#define DEFINE_GUEST_HANDLE(type)
+#define GUEST_HANDLE(type)        type *
+#endif
+
+#ifndef __ASSEMBLY__
+/* Guest handle for unsigned long pointer. Define a name with no whitespace. */
+typedef unsigned long xen_ulong;
+DEFINE_GUEST_HANDLE(xen_ulong);
+/* Guest handle for arbitrary-type pointer (void *). */
+DEFINE_GUEST_HANDLE(void);
+#endif
+
 #if defined(__i386__)
 #include "arch-x86_32.h"
 #elif defined(__x86_64__)
diff --git a/xen/include/xen/guest_access.h b/xen/include/xen/guest_access.h
new file mode 100644 (file)
index 0000000..3a5bba9
--- /dev/null
@@ -0,0 +1,71 @@
+/******************************************************************************
+ * guest_access.h
+ * 
+ * Copyright (x) 2006, K A Fraser
+ */
+
+#ifndef __XEN_GUEST_ACCESS_H__
+#define __XEN_GUEST_ACCESS_H__
+
+#include <asm/uaccess.h>
+
+/* Is the guest handle a NULL reference? */
+#define guest_handle_is_null(hnd)        ((hnd).p == NULL)
+
+/* Offset the given guest handle into the array it refers to. */
+#define guest_handle_add_offset(hnd, nr) ((hnd).p += (nr))
+
+/* Cast a guest handle to the specified type of handle. */
+#define guest_handle_cast(hnd, type) ({         \
+    type *_x = (hnd).p;                         \
+    (GUEST_HANDLE(type)) { _x };                \
+})
+
+/*
+ * Copy an array of objects to guest context via a guest handle.
+ * Optionally specify an offset into the guest array.
+ */
+#define copy_to_guest_offset(hnd, off, ptr, nr) ({      \
+    const typeof(ptr) _x = (hnd).p;                     \
+    const typeof(ptr) _y = (ptr);                       \
+    copy_to_user(_x+(off), _y, sizeof(*_x)*(nr));       \
+})
+#define copy_to_guest(hnd, ptr, nr)                     \
+    copy_to_guest_offset(hnd, 0, ptr, nr)
+
+/*
+ * Copy an array of objects from guest context via a guest handle.
+ * Optionally specify an offset into the guest array.
+ */
+#define copy_from_guest_offset(ptr, hnd, off, nr) ({    \
+    const typeof(ptr) _x = (hnd).p;                     \
+    const typeof(ptr) _y = (ptr);                       \
+    copy_from_user(_y, _x+(off), sizeof(*_x)*(nr));     \
+})
+#define copy_from_guest(ptr, hnd, nr)                   \
+    copy_from_guest_offset(ptr, hnd, 0, nr)
+
+/*
+ * Pre-validate a guest handle.
+ * Allows use of faster __copy_* functions.
+ */
+#define guest_handle_okay(hnd, nr)                      \
+    array_access_ok((hnd).p, (nr), sizeof(*(hnd).p))
+
+#define __copy_to_guest_offset(hnd, off, ptr, nr) ({    \
+    const typeof(ptr) _x = (hnd).p;                     \
+    const typeof(ptr) _y = (ptr);                       \
+    __copy_to_user(_x+(off), _y, sizeof(*_x)*(nr));     \
+})
+#define __copy_to_guest(hnd, ptr, nr)                   \
+    __copy_to_guest_offset(hnd, 0, ptr, nr)
+
+#define __copy_from_guest_offset(ptr, hnd, off, nr) ({  \
+    const typeof(ptr) _x = (hnd).p;                     \
+    const typeof(ptr) _y = (ptr);                       \
+    __copy_from_user(_y, _x+(off), sizeof(*_x)*(nr));   \
+})
+#define __copy_from_guest(ptr, hnd, nr)                 \
+    __copy_from_guest_offset(ptr, hnd, 0, nr)
+
+#endif /* __XEN_GUEST_ACCESS_H__ */
index 91f457702a4efb6b2abcb254ed48d9566de7ece4..2d9c5564d1228839d855171a9f3a1bcbe26ddd38 100644 (file)
@@ -303,31 +303,18 @@ extern void continue_running(
 
 void startup_cpu_idle_loop(void);
 
-unsigned long __hypercall_create_continuation(
-    unsigned int op, unsigned int nr_args, ...);
-#define hypercall0_create_continuation(_op)                               \
-    __hypercall_create_continuation((_op), 0)
-#define hypercall1_create_continuation(_op, _a1)                          \
-    __hypercall_create_continuation((_op), 1,                             \
-        (unsigned long)(_a1))
-#define hypercall2_create_continuation(_op, _a1, _a2)                     \
-    __hypercall_create_continuation((_op), 2,                             \
-        (unsigned long)(_a1), (unsigned long)(_a2))
-#define hypercall3_create_continuation(_op, _a1, _a2, _a3)                \
-    __hypercall_create_continuation((_op), 3,                             \
-        (unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3))
-#define hypercall4_create_continuation(_op, _a1, _a2, _a3, _a4)           \
-    __hypercall_create_continuation((_op), 4,                             \
-        (unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3), \
-        (unsigned long)(_a4))
-#define hypercall5_create_continuation(_op, _a1, _a2, _a3, _a4, _a5)      \
-    __hypercall_create_continuation((_op), 5,                             \
-        (unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3), \
-        (unsigned long)(_a4), (unsigned long)(_a5))
-#define hypercall6_create_continuation(_op, _a1, _a2, _a3, _a4, _a5, _a6) \
-    __hypercall_create_continuation((_op), 6,                             \
-        (unsigned long)(_a1), (unsigned long)(_a2), (unsigned long)(_a3), \
-        (unsigned long)(_a4), (unsigned long)(_a5), (unsigned long)(_a6))
+/*
+ * Creates a continuation to resume the current hypercall. The caller should
+ * return immediately, propagating the value returned from this invocation.
+ * The format string specifies the types and number of hypercall arguments.
+ * It contains one character per argument as follows:
+ *  'i' [unsigned] {char, int}
+ *  'l' [unsigned] long
+ *  'p' pointer (foo *)
+ *  'h' guest handle (GUEST_HANDLE(foo))
+ */
+unsigned long hypercall_create_continuation(
+    unsigned int op, const char *format, ...);
 
 #define hypercall_preempt_check() (unlikely(    \
         softirq_pending(smp_processor_id()) |   \